// Clang 驱动器
// 使用 Clang 编译 LLVM IR 到可执行文件

const std = @import("std");

pub const ClangDriver = struct {
    allocator: std.mem.Allocator,
    clang_path: []const u8,
    
    pub fn init(allocator: std.mem.Allocator) !ClangDriver {
        // 查找 Clang
        const clang_path = findClang(allocator) catch "clang";
        
        return .{
            .allocator = allocator,
            .clang_path = clang_path,
        };
    }
    
    /// 编译 LLVM IR 到目标文件
    pub fn compileIR(
        self: *ClangDriver,
        ir_path: []const u8,
        output_path: []const u8,
        optimize: OptimizeLevel,
    ) !void {
        const opt_flag = switch (optimize) {
            .debug => "-O0",
            .release_safe => "-O2",
            .release_fast => "-O3",
            .release_small => "-Os",
        };
        
        var args = std.ArrayList([]const u8).init(self.allocator);
        defer args.deinit();
        
        try args.appendSlice(&[_][]const u8{
            self.clang_path,
            "-x", "ir",           // 输入是 LLVM IR
            ir_path,
            opt_flag,
            "-o", output_path,
            "-lc",                // 链接 C 标准库
        });
        
        std.debug.print("Running: {s}\n", .{try std.mem.join(self.allocator, " ", args.items)});
        
        var child = std.ChildProcess.init(args.items, self.allocator);
        const result = try child.spawnAndWait();
        
        if (result != .Exited or result.Exited != 0) {
            return error.CompilationFailed;
        }
    }
    
    /// 直接编译 C 代码（用于互操作）
    pub fn compileC(
        self: *ClangDriver,
        c_path: []const u8,
        output_path: []const u8,
        optimize: OptimizeLevel,
    ) !void {
        const opt_flag = switch (optimize) {
            .debug => "-O0",
            .release_safe => "-O2",
            .release_fast => "-O3",
            .release_small => "-Os",
        };
        
        var args = std.ArrayList([]const u8).init(self.allocator);
        defer args.deinit();
        
        try args.appendSlice(&[_][]const u8{
            self.clang_path,
            c_path,
            opt_flag,
            "-o", output_path,
        });
        
        var child = std.ChildProcess.init(args.items, self.allocator);
        const result = try child.spawnAndWait();
        
        if (result != .Exited or result.Exited != 0) {
            return error.CompilationFailed;
        }
    }
    
    /// 链接多个目标文件
    pub fn link(
        self: *ClangDriver,
        object_files: []const []const u8,
        output_path: []const u8,
    ) !void {
        var args = std.ArrayList([]const u8).init(self.allocator);
        defer args.deinit();
        
        try args.append(self.clang_path);
        try args.appendSlice(object_files);
        try args.appendSlice(&[_][]const u8{
            "-o", output_path,
        });
        
        var child = std.ChildProcess.init(args.items, self.allocator);
        const result = try child.spawnAndWait();
        
        if (result != .Exited or result.Exited != 0) {
            return error.LinkingFailed;
        }
    }
};

pub const OptimizeLevel = enum {
    debug,
    release_safe,
    release_fast,
    release_small,
};

fn findClang(allocator: std.mem.Allocator) ![]const u8 {
    // 尝试常见的 Clang 路径
    const paths = [_][]const u8{
        "clang",
        "/usr/bin/clang",
        "/usr/local/bin/clang",
        "C:\\Program Files\\LLVM\\bin\\clang.exe",
    };
    
    for (paths) |path| {
        // 测试是否可执行
        var child = std.ChildProcess.init(&[_][]const u8{path, "--version"}, allocator);
        const result = child.spawnAndWait() catch continue;
        
        if (result == .Exited and result.Exited == 0) {
            return try allocator.dupe(u8, path);
        }
    }
    
    return error.ClangNotFound;
}
